package com.manlitech.cloudboot.basebootconfig.exception;


import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.alibaba.fastjson.JSON;
import com.manlitech.cloudboot.common.enums.ResultEnums;
import com.manlitech.cloudboot.common.utils.Result;
import com.manlitech.cloudboot.common.utils.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.crypto.MacSpi;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.ResultSet;


@ControllerAdvice
@Component
public class ExceptionHandle {
	
	private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
	
	@ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result handle(Exception e) {
		//logger.error("exceptionmsg="+e.getMessage());
        if (e instanceof MyException) {
        	MyException myException = (MyException) e;
            return ResultUtil.error(myException.getCode(), myException.getMessage());
        }else if(e instanceof BlockException){
			BlockException blockException = (BlockException) e;
			Result result = blockExceptionHandler(blockException);
			logger.error(JSON.toJSONString(result));
			return result;
		}else {
            //logger.error("【系统异常】"+e.getStackTrace());
			e.printStackTrace();
			String message = getExceptionToString(e);
			// 可能由于运行是sentinel发出的runtimeException
			Result sentinelResult = ExceptionHandle.isSentinelRuntimeException(message);
			if(sentinelResult != null){
				return sentinelResult;
			}
			return ResultUtil.error(ResultEnums.UNKONW_ERROR.getCode(),ResultEnums.UNKONW_ERROR.getMsg(),message);
        }
    }

	private Result blockExceptionHandler(BlockException e) {
		if (e instanceof FlowException) {
			return ResultUtil.error(ResultEnums.API_FLOW_EXCEPTION.getCode(),ResultEnums.API_FLOW_EXCEPTION.getMsg());
		} else if (e instanceof DegradeException) {
			return ResultUtil.error(ResultEnums.API_DEGRADE_EXCEPTION.getCode(),ResultEnums.API_DEGRADE_EXCEPTION.getMsg());
		} else if (e instanceof ParamFlowException) {
			return ResultUtil.error(ResultEnums.API_PARAM_HOT_FLOW_EXCEPTION.getCode(),ResultEnums.API_PARAM_HOT_FLOW_EXCEPTION.getMsg());
		} else if (e instanceof SystemBlockException) {
			return ResultUtil.error(ResultEnums.API_SYSTEM_BLOCK_EXCEPTION.getCode(),ResultEnums.API_SYSTEM_BLOCK_EXCEPTION.getMsg());
		} else if (e instanceof AuthorityException) {
			return ResultUtil.error(ResultEnums.API_AUTHORITY_EXCEPTION.getCode(),ResultEnums.API_AUTHORITY_EXCEPTION.getMsg());
		}
		return null;
	}

	private static Result isSentinelRuntimeException(String message) {
		if (message.contains("FlowException")) {
			return ResultUtil.error(ResultEnums.API_FLOW_EXCEPTION.getCode(),ResultEnums.API_FLOW_EXCEPTION.getMsg());
		} else if (message.contains("DegradeException")) {
			return ResultUtil.error(ResultEnums.API_DEGRADE_EXCEPTION.getCode(),ResultEnums.API_DEGRADE_EXCEPTION.getMsg());
		} else if (message.contains("ParamFlowException")) {
			return ResultUtil.error(ResultEnums.API_PARAM_HOT_FLOW_EXCEPTION.getCode(),ResultEnums.API_PARAM_HOT_FLOW_EXCEPTION.getMsg());
		} else if (message.contains("SystemBlockException")) {
			return ResultUtil.error(ResultEnums.API_SYSTEM_BLOCK_EXCEPTION.getCode(),ResultEnums.API_SYSTEM_BLOCK_EXCEPTION.getMsg());
		} else if (message.contains("AuthorityException")) {
			return ResultUtil.error(ResultEnums.API_AUTHORITY_EXCEPTION.getCode(),ResultEnums.API_AUTHORITY_EXCEPTION.getMsg());
		}
		return null;
	}

	public static String getExceptionToString(Throwable e) {
		if (e == null){
			return "";
		}
		StringWriter stringWriter = new StringWriter();
		e.printStackTrace(new PrintWriter(stringWriter));
		String message = stringWriter.toString().split("\n")[0];
		// 排除dubboRpcException 干扰
		message = ExceptionHandle.ignoreDubboRpcException(message);

		return message ;
	}

	public static String ignoreDubboRpcException(String msg){
		if(msg.startsWith("org.apache.dubbo.rpc.RpcException") && msg.indexOf("cause:")>-1){
			msg = msg.split("cause:")[1];
		}
		return msg;
	}





}
